import type {ApiOptions, DefaultApiOptions, DefineApi} from "./types";
import {parseApiOptions} from "~/utils/fetch/_helper";
import {FetchError} from "ofetch";
import {isUndefined} from "lodash-es";
import {ApiError} from "./error";
import type {Ref} from "vue";

export function createDefineApi(opts?: DefaultApiOptions): DefineApi {
    const defuOpts = { ...opts }
    const _fetch = $fetch.create(defuOpts)
    return (options: ApiOptions): any => {
        return {
            async fetch(params?: Record<string, any>) {
                try {
                    const opts = parseApiOptions(options, params)
                    return await _fetch(opts.url, opts)
                } catch (err) {
                    if (err instanceof FetchError && isUndefined(err.statusCode)) {
                        throw new ApiError('[api]: Failed to connected network', ReturnCode.INTERNET_DISCONNECTED)
                    } else {
                        throw new ApiError((err as any)?.message ?? `Failed to request ${options.url}`)
                    }
                }
            },
            async useFetch(params?: Record<string, any>) {
                const _opts = parseApiOptions(options, params)
                const resp = await useFetch(_opts.url, {
                    ..._opts,
                    $fetch: async (url: string, opts: any = {})=> {
                        try {
                            return await _fetch(url, opts)
                        } catch (err) {
                            if (err instanceof FetchError && isUndefined(err.statusCode)) {
                                throw new ApiError('[api]: Failed to connected network', ReturnCode.INTERNET_DISCONNECTED)
                            } else {
                                throw new ApiError((err as any)?.message ?? `Failed to request ${url}`)
                            }
                        }
                    },
                })
                const data = computed<any>({
                    get() {
                        const data: Ref<any> = resp.data
                        return data.value?.data
                    },
                    set(val: any) {
                        ;(resp.data.value as any).data = val
                    }
                })
                return [data, resp]
            }
        }
    }
}
